﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using MathematicallySafe.HeadCounter.Data.Common;
using MathematicallySafe.HeadCounter.Data.Interfaces;
using MathematicallySafe.HeadCounter.Data.Models;
using StructureMap;

namespace MathematicallySafe.HeadCounter.Data
{
    public class HeadCounterService: IHeadCounterService, IDisposable
    {
        private IOptions _options;
        private IUserOptions _userOptions;
        private IGuild _guild;
        private IRaidHistory _raidHistory;
        private ILootTable _lootTable;

        public HeadCounterService(IOptions options, IUserOptions userOptions, IGuild guild, IRaidHistory raidHistory, ILootTable lootTable)
        {
            _options = options;
            _userOptions = userOptions;
            _guild = guild;
            _raidHistory = raidHistory;
            _lootTable = lootTable;
        }

        public void Initialise()
        {
            _guild.SubscribeEvents();
            SubscribeEvents();
            SetClean();
        }

        public void Save()
        {
            _options.Save();
            _userOptions.Save();
            _guild.Save();
            _raidHistory.Save();
            _lootTable.Save();

            SetClean();
        }

        public bool IsDirty
        {
            get
            {
                return _options.IsDirty || _userOptions.IsDirty || _guild.IsDirty || _raidHistory.IsDirty || _lootTable.IsDirty;
            }
        }
        
        public bool IsClean { get { return !IsDirty; } }

        public void SetDirty()
        {
            _options.SetDirty();
            _userOptions.SetDirty();
            _guild.SetDirty();
            _raidHistory.SetDirty();
            _lootTable.SetDirty();
        }

        public void SetClean()
        {
            _options.SetDirty();
            _userOptions.SetDirty();
            _guild.SetDirty();
            _raidHistory.SetDirty();
            _lootTable.SetDirty();
        }

        #region events

        private void SubscribeEvents()
        {
            _guild.RaiderAdded += GuildRaiderAdded;
            _guild.RaiderRemoved += GuildRaiderRemoved;
            _raidHistory.RaidAdded += RaidHistoryRaidAdded;
            _raidHistory.RaidRemoved += RaidHistoryRaidRemoved;
        }

        private void UnsubscribeEvents()
        {
            _guild.RaiderAdded -= GuildRaiderAdded;
            _guild.RaiderRemoved -= GuildRaiderRemoved;
            _raidHistory.RaidAdded -= RaidHistoryRaidAdded;
            _raidHistory.RaidRemoved -= RaidHistoryRaidRemoved;
        }

        void GuildRaiderAdded(object sender, RosterChangedEventArgs e)
        {
            SetDirty();
        }

        void GuildRaiderRemoved(object sender, RosterChangedEventArgs e)
        {
            SetDirty();
        }

        void RaidHistoryRaidAdded(object sender, RaidsHistoryChangedEventArgs e)
        {
            SetDirty();
        }

        void RaidHistoryRaidRemoved(object sender, RaidsHistoryChangedEventArgs e)
        {
            var doomed = new List<string>();

            _guild.Raiders.ForEach(raider =>
            {
                var firstRaid = _raidHistory.Raids.Where(raid => raid.RaiderAttendedAnyChar(raider.Name)).FirstOrDefault();

                if (firstRaid == null)
                {
                    doomed.Add(raider.Identity);
                }
            });

            doomed.ForEach(d => _guild.RemoveRaider(d));
            SetDirty();
        }

        #endregion

        public void Dispose()
        {
            UnsubscribeEvents();
        }
    }
}